import sys
import os
import hashlib
import threading
from datetime import datetime
from pathlib import Path

from PySide6.QtWidgets import (QApplication, QMainWindow, QVBoxLayout, QHBoxLayout, 
                               QWidget, QMenuBar, QMenu, QFileDialog, QTableWidget, 
                               QTableWidgetItem, QProgressDialog, QDialog, QComboBox, 
                               QPushButton, QLabel, QDialogButtonBox, QMessageBox)
from PySide6.QtCore import Qt, QThread, Signal, QObject
from PySide6.QtGui import QAction, QClipboard


class FileInfo:
    def __init__(self, file_path):
        self.file_path = file_path
        self.file_name = os.path.basename(file_path)
        self.file_size = os.path.getsize(file_path)
        self.create_time = datetime.fromtimestamp(os.path.getctime(file_path)).strftime('%Y-%m-%d %H:%M:%S')
        self.hash_value = ""
        self.hash_algorithm = "md5"

    def get_formatted_size(self):
        """返回格式化的文件大小"""
        size = self.file_size
        for unit in ['B', 'KiB', 'MiB', 'GiB', 'TiB']:
            if size < 1024.0:
                return f"{size:.2f} {unit}"
            size /= 1024.0
        return f"{size:.2f} PiB"


class HashCalculator(QThread):
    progress_updated = Signal(int)
    file_processed = Signal(FileInfo)
    finished = Signal()
    
    def __init__(self, file_paths, algorithm="md5"):
        super().__init__()
        self.file_paths = file_paths
        self.algorithm = algorithm
        self._is_running = True
        
    def run(self):
        total_files = len(self.file_paths)
        for i, file_path in enumerate(self.file_paths):
            if not self._is_running:
                break
                
            try:
                file_info = FileInfo(file_path)
                file_info.hash_algorithm = self.algorithm
                
                # 计算哈希值
                hash_obj = hashlib.new(self.algorithm)
                with open(file_path, 'rb') as f:
                    for chunk in iter(lambda: f.read(8192), b""):
                        if not self._is_running:
                            break
                        hash_obj.update(chunk)
                
                if self._is_running:
                    file_info.hash_value = hash_obj.hexdigest()
                    self.file_processed.emit(file_info)
                
            except Exception as e:
                file_info = FileInfo(file_path)
                file_info.hash_value = f"错误: {str(e)}"
                self.file_processed.emit(file_info)
            
            progress = int((i + 1) * 100 / total_files)
            self.progress_updated.emit(progress)
        
        self.finished.emit()
    
    def stop(self):
        self._is_running = False


class SettingsDialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle("设置")
        self.setFixedSize(300, 150)
        
        layout = QVBoxLayout()
        
        # 算法选择
        algorithm_label = QLabel("哈希算法:")
        self.algorithm_combo = QComboBox()
        self.algorithm_combo.addItems(["md5", "sha1", "sha256"])
        
        # 获取当前设置
        current_algorithm = parent.settings.get("algorithm", "md5")
        index = self.algorithm_combo.findText(current_algorithm)
        if index >= 0:
            self.algorithm_combo.setCurrentIndex(index)
        
        layout.addWidget(algorithm_label)
        layout.addWidget(self.algorithm_combo)
        
        # 按钮
        buttons = QDialogButtonBox(QDialogButtonBox.Save | QDialogButtonBox.Cancel)
        buttons.accepted.connect(self.accept)
        buttons.rejected.connect(self.reject)
        layout.addWidget(buttons)
        
        self.setLayout(layout)
    
    def get_selected_algorithm(self):
        return self.algorithm_combo.currentText()


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("PyHashCalculator")
        self.setGeometry(100, 100, 800, 600)
        
        # 设置存储
        self.settings = {"algorithm": "md5"}
        
        # 当前计算线程
        self.current_calculator = None
        
        self.init_ui()
        
    def init_ui(self):
        # 创建菜单栏
        menubar = self.menuBar()
        file_menu = menubar.addMenu("文件")
        
        # 导入文件动作
        import_file_action = QAction("导入文件", self)
        import_file_action.triggered.connect(self.import_file)
        file_menu.addAction(import_file_action)
        
        # 导入目录动作
        import_dir_action = QAction("导入目录", self)
        import_dir_action.triggered.connect(self.import_directory)
        file_menu.addAction(import_dir_action)
        
        # 设置动作
        settings_action = QAction("设置", self)
        settings_action.triggered.connect(self.show_settings)
        file_menu.addAction(settings_action)
        
        # 退出动作
        exit_action = QAction("退出", self)
        exit_action.triggered.connect(self.close)
        file_menu.addAction(exit_action)
        
        # 创建中心部件
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        
        # 创建主布局
        main_layout = QVBoxLayout()
        central_widget.setLayout(main_layout)
        
        # 创建表格
        self.table_widget = QTableWidget()
        self.table_widget.setColumnCount(5)
        self.table_widget.setHorizontalHeaderLabels(["文件名", "创建时间", "大小", "路径", "哈希值"])
        self.table_widget.setAlternatingRowColors(True)
        
        # 设置列宽
        header = self.table_widget.horizontalHeader()
        header.setSectionResizeMode(0, header.ResizeMode.ResizeToContents)
        header.setSectionResizeMode(1, header.ResizeMode.ResizeToContents)
        header.setSectionResizeMode(2, header.ResizeMode.ResizeToContents)
        header.setSectionResizeMode(3, header.ResizeMode.Stretch)
        header.setSectionResizeMode(4, header.ResizeMode.ResizeToContents)
        
        main_layout.addWidget(self.table_widget)
        
        # 创建底部按钮区域
        bottom_layout = QHBoxLayout()
        
        self.copy_button = QPushButton("复制结果")
        self.copy_button.clicked.connect(self.copy_results)
        self.copy_button.setEnabled(False)
        
        bottom_layout.addStretch()
        bottom_layout.addWidget(self.copy_button)
        
        main_layout.addLayout(bottom_layout)
        
    def import_file(self):
        file_path, _ = QFileDialog.getOpenFileName(self, "选择文件", "", "All Files (*)")
        if file_path:
            self.process_files([file_path])
    
    def import_directory(self):
        dir_path = QFileDialog.getExistingDirectory(self, "选择目录")
        if dir_path:
            file_paths = []
            for root, dirs, files in os.walk(dir_path):
                for file in files:
                    file_paths.append(os.path.join(root, file))
            if file_paths:
                self.process_files(file_paths)
            else:
                QMessageBox.information(self, "提示", "目录中没有文件")
    
    def process_files(self, file_paths):
        if self.current_calculator and self.current_calculator.isRunning():
            QMessageBox.warning(self, "警告", "正在处理中，请稍候...")
            return
        
        # 清空现有表格内容
        self.table_widget.setRowCount(0)
        self.copy_button.setEnabled(False)
        
        # 创建进度对话框
        self.progress_dialog = QProgressDialog("正在计算哈希值...", "取消", 0, 100, self)
        self.progress_dialog.setWindowModality(Qt.WindowModal)
        self.progress_dialog.setAutoClose(True)
        self.progress_dialog.canceled.connect(self.cancel_calculation)
        
        # 创建计算线程
        self.current_calculator = HashCalculator(file_paths, self.settings["algorithm"])
        self.current_calculator.progress_updated.connect(self.progress_dialog.setValue)
        self.current_calculator.file_processed.connect(self.add_file_to_table)
        self.current_calculator.finished.connect(self.calculation_finished)
        
        self.progress_dialog.show()
        self.current_calculator.start()
    
    def add_file_to_table(self, file_info):
        row_position = self.table_widget.rowCount()
        self.table_widget.insertRow(row_position)
        
        self.table_widget.setItem(row_position, 0, QTableWidgetItem(file_info.file_name))
        self.table_widget.setItem(row_position, 1, QTableWidgetItem(file_info.create_time))
        self.table_widget.setItem(row_position, 2, QTableWidgetItem(file_info.get_formatted_size()))
        self.table_widget.setItem(row_position, 3, QTableWidgetItem(file_info.file_path))
        self.table_widget.setItem(row_position, 4, QTableWidgetItem(file_info.hash_value))
    
    def calculation_finished(self):
        if self.progress_dialog:
            self.progress_dialog.close()
        self.current_calculator = None
        
        # 如果有计算结果，启用复制按钮
        if self.table_widget.rowCount() > 0:
            self.copy_button.setEnabled(True)
    
    def copy_results(self):
        """复制结果到剪贴板"""
        if self.table_widget.rowCount() == 0:
            return
        
        results = []
        for row in range(self.table_widget.rowCount()):
            file_name = self.table_widget.item(row, 0).text()
            file_size = self.table_widget.item(row, 2).text()
            hash_value = self.table_widget.item(row, 4).text()
            
            results.append(f"文件名称：{file_name}")
            results.append(f"文件大小：{file_size}")
            results.append(f"哈希值：{hash_value}")
            results.append("-" * 17)
        
        results.append(f"共计{self.table_widget.rowCount()}个文件。")
        
        clipboard_text = "\n".join(results)
        QApplication.clipboard().setText(clipboard_text)
        
        QMessageBox.information(self, "提示", "结果已复制到剪贴板！")
    
    def cancel_calculation(self):
        if self.current_calculator:
            self.current_calculator.stop()
    
    def show_settings(self):
        dialog = SettingsDialog(self)
        if dialog.exec() == QDialog.Accepted:
            self.settings["algorithm"] = dialog.get_selected_algorithm()
            QMessageBox.information(self, "提示", f"已设置哈希算法为: {self.settings['algorithm']}")


def main():
    app = QApplication(sys.argv)
    
    # 设置应用程序样式
    app.setStyle('Fusion')
    
    window = MainWindow()
    window.show()
    
    sys.exit(app.exec())


if __name__ == "__main__":
    main()